#ifndef CLIENT_MAKEFILE_DEPS_H_
#define CLIENT_MAKEFILE_DEPS_H_

#include "deps.h"

#include <map>
#include <string>
#include <vector>

#include <pthread.h>

#include "observer.h"

using std::map;
using std::vector;
using std::string;

enum STRATEGY {
  RANDOM,
  PRIORITY
};

/**
* Takes in a Makefile and creates a dependency tree out of it
*/
class MakefileDeps : public Observer {

  public:
  MakefileDeps();
  MakefileDeps(char* make_file);
  MakefileDeps(char* make_file, char* cc_filename, char* link_filename);
  ~MakefileDeps();
  void Initialize();
  Deps* GetDependencyGraph();
  inline vector<Deps*>& GetLeafDeps();
  inline int lockLeafList() {
	  return pthread_mutex_lock(&leaf_list_lock_);
  }
  inline int unlockLeafList() {
	  return pthread_mutex_unlock(&leaf_list_lock_);
  }
  inline int leafListSize() {
	  pthread_mutex_lock(&leaf_list_lock_);
	  int ret = leaf_deps_.size();
	  pthread_mutex_unlock(&leaf_list_lock_);
	  return ret;
  }

  // Implementation of Observer's virtual methods
  virtual void Update(UpdateInfo update_info);
  void AssignPriorities();
  void SetExecutionTime(char * compile_time_file);
  void SetHeuristics();
  inline void set_strategy(STRATEGY strategy);
  Deps* GetNextLeafToSchedule();
  inline int total_deps();
  inline int max_parallelism();

  private:
  void ConstructDependencyGraph(char* finame);
  void AddDependency(string target_str, string deps_str, map<string, Deps*>
      &deps_map);
  void RemoveFromLeafList(Deps* deps);
  void AddToLeafList(Deps* deps);
  void AddLevelCount(Deps* deps, int level);
  void AddLevelCount();
  void AssignPriorities(vector<Deps*> deps_children, string parent_priority,
      int level);
  void SetHeuristics(Deps* deps);
  Deps* RemoveFromMaxLeafHeap();
  Deps* RemoveRandomLeaf();

  char* make_file_;
  char* cc_time_filename_;
  char* link_time_filename_;
  Deps* deps_graph_;
  vector<int> num_child_level_;
  int total_deps_;
  int max_parallelism_;

  map<string, Deps*> topmost_deps_map_;
  map<string, Deps*> leaf_deps_map_;
  map<string, Deps*> deps_map_;
  vector<Deps*> leaf_deps_;
  pthread_mutex_t leaf_list_lock_;
  vector<int> num_bits_level_;
  int total_bits_;
  STRATEGY strategy_;
};

inline vector<Deps*>& MakefileDeps::GetLeafDeps() {
  return this->leaf_deps_;
}

inline void MakefileDeps::set_strategy(STRATEGY strategy) {
  strategy_ = strategy;
}

inline int MakefileDeps::total_deps() {
  return total_deps_;
}

inline int MakefileDeps::max_parallelism() {
  return max_parallelism_;
}

#endif  // CLIENT_MAKEFILE_DEPS_H_
